//
// Created on 2024/4/26.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "Context.h"
#include "models/NativeBasic.h"
#include "models/NativeObject.h"

namespace rcim {
namespace context {

/**
 * 线程安全函数，适用于只有一个 Callback 或者只有一个 Listener 方法
 * 发送消息接口不能用，其他接口都可以用
 * */
struct ThreadSafeFunction {
    // 线程安全的方法，需要通过 ArkTS 层的 Callback 或者 Listener 创建
    // 只触发一次的 Callback 需要删除；多次触发的 Listener 不能删除
    napi_threadsafe_function func = nullptr;
    // Rust 引擎实例
    const Engine *engine_ = nullptr;
};

/**
 * 初始化线程安全函数
 * @param func 线程安全函数
 */
void InitThreadSafeFunction(ThreadSafeFunction &func) {
    func.func = nullptr;
    func.engine_ = nullptr;
}

void *_genContextByFunction(const Engine *engine, napi_env env, napi_value function_value,
                            napi_threadsafe_function_call_js call_js_cb) {
    // 把 env，Callback 保存到 ThreadSafeFunction
    ThreadSafeFunction threadSafeFunction;
    InitThreadSafeFunction(threadSafeFunction);
    threadSafeFunction.engine_ = engine;

    // 创建操作的名称，有点像线程名称
    napi_value resourceName = nullptr;
    napi_create_string_utf8(env, "RcimNapiThreadSafeFunction", NAPI_AUTO_LENGTH, &resourceName);

    void *cbContext = &threadSafeFunction;
    napi_create_threadsafe_function(env, function_value, nullptr, resourceName, 0, 1, nullptr, nullptr, cbContext,
                                    call_js_cb, &threadSafeFunction.func);

    // 使用 make_unique 将 ThreadSafeFunction 指针变成动态指针，确保连接成功后 ThreadSafeFunction 依旧生效
    // 如果直接用 ThreadSafeFunction 当做上下文，连接成功后 ThreadSafeFunction 就失效了
    // 原因：ThreadSafeFunction 默认为栈区，出了方法就会失效；连接接口内部会做网络切换，栈区数据会失效
    auto dataPtr = std::make_unique<ThreadSafeFunction>(std::move(threadSafeFunction));
    void *context = dataPtr.release();
    return context;
}

/**
 * 线程安全函数的数据，用于跨线程传递数据
 */
struct ThreadSafeFunctionVectorData {
    std::vector<NativeObject *> *args_vec;
};

// Listener 相关 *******************************************************
void threadSafeListenerAdapterCallJs(napi_env env, napi_value jsCb, void *context, void *data) {
    // 将 callArkTSCallbackForAsyncMethod 传过来的 ThreadSafeFunctionVectorData 读出来
    ThreadSafeFunctionVectorData mData = *(static_cast<ThreadSafeFunctionVectorData *>(data));

    const uint32_t ret_argc = mData.args_vec->size();
    napi_value ret_args[ret_argc];

    if (ret_argc > 0) {
        for (int i = 0; i < ret_argc; i++) {
            NativeObject *obj = (*mData.args_vec)[i];
            napi_value value = obj->toValue(env);
            ret_args[i] = value;
            delete obj;
        }
    }
    if (mData.args_vec != nullptr) {
        delete mData.args_vec;
    }

    napi_value undefined;
    napi_get_undefined(env, &undefined);
    napi_value result;
    napi_call_function(env, undefined, jsCb, ret_argc, ret_args, &result);
}

void *genContextByListener(const Engine *engine, napi_env env, napi_value listener_value) {
    return _genContextByFunction(engine, env, listener_value, threadSafeListenerAdapterCallJs);
}

const Engine *getEngineFromContextByListener(const void *context) {
    const ThreadSafeFunction *threadSafeFunction = static_cast<const ThreadSafeFunction *>(context);
    return threadSafeFunction->engine_;
}

/**
 * 调用线程安全函数
 * @param func 线程安全函数
 * @param data 需要传输的数据
 */
void _callThreadSafeFunction(napi_threadsafe_function func, void *data) {
    if (func != nullptr) {
        napi_status status = napi_acquire_threadsafe_function(func);
        if (napi_ok == status) {
            napi_call_threadsafe_function(func, data, napi_tsfn_blocking);
        }
    }
}

const napi_threadsafe_function getThreadSafeFunctionFromContext(const void *context) {
    // 将之前 void *context 转成 ThreadSafeFunction
    const ThreadSafeFunction *threadSafeFunction = static_cast<const ThreadSafeFunction *>(context);
    return threadSafeFunction->func;
}

void callArkTSListenerForAsyncMethod(const void *context, std::vector<NativeObject *> *vec) {

    // 将之前 void *context 转成 ThreadSafeFunction
    const ThreadSafeFunction *threadSafeFunction = static_cast<const ThreadSafeFunction *>(context);

    ThreadSafeFunctionVectorData mData;
    mData.args_vec = vec;

    void *data = std::make_unique<ThreadSafeFunctionVectorData>(std::move(mData)).release();
    _callThreadSafeFunction(threadSafeFunction->func, data);
}

} // namespace context
} // namespace rcim